﻿// Copyright (c) Inossem. All rights reserved.
// Licensed under the LGPL-3.0 license. See LICENSE file in the project root for full license information.
using DWF.Studio.Custom;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Media;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WpfMessageBoxLibrary;

namespace DWF.Studio.Views
{
    /// <summary>
    /// WindowScriptFindReplace.xaml 的交互逻辑
    /// </summary>
    public partial class WindowScriptFindReplace
    {
        private static string _textToFind = "";
        private static bool _caseSensitive = true;
        private static bool _wholeWord = true;
        private static bool _useRegex = false;
        private static bool _useWildcards = false;
        private static bool _searchUp = false;

        private Func<TextEditor> _curretnEditor = null;

        public WindowScriptFindReplace(Func<TextEditor> getCurretnEditor)
        {
            InitializeComponent();

            this._curretnEditor = getCurretnEditor;
            init();
        }

        private void init()
        {
            txtFind.Text = txtFind2.Text = _textToFind;
            cbCaseSensitive.IsChecked = _caseSensitive;
            cbWholeWord.IsChecked = _wholeWord;
            cbRegex.IsChecked = _useRegex;
            cbWildcards.IsChecked = _useWildcards;
            cbSearchUp.IsChecked = _searchUp;
        }

        private void Window_Closed(object sender, System.EventArgs e)
        {
            _textToFind = txtFind2.Text;
            _caseSensitive = (cbCaseSensitive.IsChecked == true);
            _wholeWord = (cbWholeWord.IsChecked == true);
            _useRegex = (cbRegex.IsChecked == true);
            _useWildcards = (cbWildcards.IsChecked == true);
            _searchUp = (cbSearchUp.IsChecked == true);

            _winFindReplace = null;
        }

        private void FindNextClick(object sender, RoutedEventArgs e)
        {
            if (!FindNext(txtFind.Text))
                SystemSounds.Beep.Play();
        }

        private void FindNext2Click(object sender, RoutedEventArgs e)
        {
            if (!FindNext(txtFind2.Text))
                SystemSounds.Beep.Play();
        }

        private void ReplaceClick(object sender, RoutedEventArgs e)
        {
            var editor = _curretnEditor();
            if (editor != null)
            {
                Regex regex = GetRegEx(txtFind2.Text);
                string input = editor.Text.Substring(editor.SelectionStart, editor.SelectionLength);
                Match match = regex.Match(input);
                bool replaced = false;
                if (match.Success && match.Index == 0 && match.Length == input.Length)
                {
                    editor.Document.Replace(editor.SelectionStart, editor.SelectionLength, txtReplace.Text);
                    replaced = true;
                }

                if (!FindNext(txtFind2.Text) && !replaced)
                    SystemSounds.Beep.Play();
            }
        }

        private void ReplaceAllClick(object sender, RoutedEventArgs e)
        {
            var editor = _curretnEditor();
            if (editor != null)
            {
                var msgProperties = new WpfMessageBoxProperties()
                {
                    Button = MessageBoxButton.OKCancel,
                    ButtonYesText = LocalizationProvider.GetLocalizedString("MessageBox_Button_OK"),
                    ButtonCancelText = LocalizationProvider.GetLocalizedString("MessageBox_Button_Cancel"),
                    Image = MessageBoxImage.Question,
                    Text = LocalizationProvider.GetLocalizedString("WindowScriptFindReplace_MsgBox_Msg_ReplaceAll"),
                    Title = LocalizationProvider.GetLocalizedString("WindowScriptFindReplace_MsgBox_Caption"),
                };

                MessageBoxResult dlgResult = WpfMessageBox.Show(this, ref msgProperties);

                if (dlgResult == MessageBoxResult.OK)
                {
                    Regex regex = GetRegEx(txtFind2.Text, true);
                    int offset = 0;
                    editor.BeginChange();
                    foreach (Match match in regex.Matches(editor.Text))
                    {
                        editor.Document.Replace(offset + match.Index, match.Length, txtReplace.Text);
                        offset += txtReplace.Text.Length - match.Length;
                    }
                    editor.EndChange();
                }
            }
        }

        private bool FindNext(string textToFind)
        {
            var result = false;
            var editor = _curretnEditor();
            if (editor != null)
            {
                Regex regex = GetRegEx(textToFind);
                int start = regex.Options.HasFlag(RegexOptions.RightToLeft) ?
                editor.SelectionStart : editor.SelectionStart + editor.SelectionLength;
                Match match = regex.Match(editor.Text, start);

                if (!match.Success)  // start again from beginning or end
                {
                    if (regex.Options.HasFlag(RegexOptions.RightToLeft))
                        match = regex.Match(editor.Text, editor.Text.Length);
                    else
                        match = regex.Match(editor.Text, 0);
                }

                if (match.Success)
                {
                    editor.Select(match.Index, match.Length);
                    TextLocation loc = editor.Document.GetLocation(match.Index);
                    editor.ScrollTo(loc.Line, loc.Column);
                }

                result = match.Success;
            }

            return result;
        }

        private Regex GetRegEx(string textToFind, bool leftToRight = false)
        {
            RegexOptions options = RegexOptions.None;
            if (cbSearchUp.IsChecked == true && !leftToRight)
                options |= RegexOptions.RightToLeft;
            if (cbCaseSensitive.IsChecked == false)
                options |= RegexOptions.IgnoreCase;

            if (cbRegex.IsChecked == true)
            {
                return new Regex(textToFind, options);
            }
            else
            {
                string pattern = Regex.Escape(textToFind);
                if (cbWildcards.IsChecked == true)
                    pattern = pattern.Replace("\\*", ".*").Replace("\\?", ".");
                if (cbWholeWord.IsChecked == true)
                    pattern = "\\b" + pattern + "\\b";
                return new Regex(pattern, options);
            }
        }

        private static WindowScriptFindReplace _winFindReplace = null;

        public static void ShowForReplace(Func<TextEditor> getCurretnEditor)
        {
            if (getCurretnEditor != null)
            {
                var editor = getCurretnEditor();
                if (editor != null)
                {
                    if (_winFindReplace == null)
                    {
                        _winFindReplace = new WindowScriptFindReplace(getCurretnEditor);
                        _winFindReplace.Owner = Application.Current.MainWindow;
                        _winFindReplace.tabMain.SelectedIndex = 1;
                        _winFindReplace.Show();
                        _winFindReplace.Activate();
                    }
                    else
                    {
                        _winFindReplace.tabMain.SelectedIndex = 1;
                        _winFindReplace.Activate();
                    }

                    if (!editor.TextArea.Selection.IsMultiline)
                    {
                        _winFindReplace.txtFind.Text = _winFindReplace.txtFind2.Text = editor.TextArea.Selection.GetText();
                        _winFindReplace.txtFind.SelectAll();
                        _winFindReplace.txtFind2.SelectAll();
                        _winFindReplace.txtFind2.Focus();
                    }
                }
            }
        }

        public static void ShowForFind(Func<TextEditor> getCurretnEditor)
        {
            if (getCurretnEditor != null)
            {
                var editor = getCurretnEditor();
                if (editor != null)
                {
                    if (_winFindReplace == null)
                    {
                        _winFindReplace = new WindowScriptFindReplace(getCurretnEditor);
                        _winFindReplace.Owner = Application.Current.MainWindow;
                        _winFindReplace.tabMain.SelectedIndex = 0;
                        _winFindReplace.Show();
                        _winFindReplace.Activate();
                    }
                    else
                    {
                        _winFindReplace.tabMain.SelectedIndex = 0;
                        _winFindReplace.Activate();
                    }

                    if (!editor.TextArea.Selection.IsMultiline)
                    {
                        _winFindReplace.txtFind.Text = _winFindReplace.txtFind2.Text = editor.TextArea.Selection.GetText();
                        _winFindReplace.txtFind.SelectAll();
                        _winFindReplace.txtFind2.SelectAll();
                        _winFindReplace.txtFind2.Focus();
                    }
                }
            }
        }
    }
}
